/**
 * Copyright (c) 2009 blurredVision
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
 * associated documentation files (the "Software"), to deal in the Software without restriction, 
 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or 
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 
 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 
 * OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include "StdAfx.h"
#include "Texture.h"
#include "dx/Renderer.h"
#include "rgbe.h"
#include "core/core.h"
#include "ResourceFactory.h"

namespace directx {

Texture::Texture()
: ITexture(),
	m_pTexture(NULL), 
	m_pVolTexture(NULL),
	m_pRenderTargetSurface(NULL),
	m_pRenderTargetDepthStencilSurface(NULL),
	m_pTextureLockable(NULL),
	m_pSurfaceLockable(NULL),
	pPixelAddress(NULL),
	m_pRTS(NULL),
	hParameters(0),
	pEffect(NULL)
{
	pd3dDevice->GetViewport(&m_sViewport);
}

Texture::~Texture(void)
{
	release();
	DELETE_POINTER(m_pScreenQuad);
}

void Texture::release()
{
	// Release the texture render target
	RELEASE(m_pRenderTargetSurface);
	// Release the depth and stencil surface of the render target
	RELEASE(m_pRenderTargetDepthStencilSurface);

	RELEASE(m_pRTS);

	RELEASE(m_pTextureLockable);
	RELEASE(m_pSurfaceLockable);
	free( pPixelAddress);

	// Release the texture object
	RELEASE(m_pTexture);

	// Release the volume texture object
	RELEASE(m_pVolTexture);
}

void Texture::reset()
{
	// Get the d3dDevice -> see DXResource
	DXResource::reset();

	if (m_bIsLoaded) {
		if ( m_bIsRenderTarget ) 
			createRenderTarget(m_iWidth, m_iHeight, m_eFormat );
		else
			load(sFilename);
	}
}

bool Texture::load(const std::string &filename, bool dynamic, eFormat format) 
{
	sFilename = filename;
	// Release all previously stored textures

	if ( filename.find("hdr") != std::string::npos ) {
		FILE* fp=0;
		fopen_s( &fp, filename.c_str(), "rb" );
	
		if (fp) {
			// Read the header information
			rgbe_header_info info;
			RGBE_ReadHeader( fp, &m_iWidth, &m_iHeight, &info );
			
			// Save the exposure and gamma values
			float fExposure = info.exposure;
			float fGamma	= info.gamma;

			// Reserve memory for the pixel data and set it to 0
			float* fHDRPixels = new float[3 * m_iWidth * m_iHeight];
			memset( fHDRPixels, 0, 3 * m_iWidth * m_iHeight * sizeof( float ) );
			
			// Read the pixel data 
			RGBE_ReadPixels_RLE( fp, fHDRPixels, m_iWidth, m_iHeight );
			// Close the file again
			fclose(fp);

			if( FAILED( D3DXCreateTexture( pd3dDevice, m_iWidth, m_iHeight, 1, D3DUSAGE_DYNAMIC, 
									   D3DFMT_A16B16G16R16F, D3DPOOL_DEFAULT, &m_pTexture ) ) )
			{
				coreGetLog()->WriteError("Unable to create HDR texture " + filename, __FILE__, __LINE__);
				return false;
			}
			
			D3DXFLOAT16* fHDR = new D3DXFLOAT16[4 * m_iWidth * m_iHeight];

			int j = 0;
			for( int i=0; i<4*m_iWidth*m_iHeight; i+=4 )
			{
				fHDR[i] = fHDRPixels[i - j];
				fHDR[i + 1] = fHDRPixels[i + 1 - j];
				fHDR[i + 2] = fHDRPixels[i + 2 - j];
				fHDR[i + 3] = 0.0f;
				++j;
			}
			
			D3DLOCKED_RECT lr;
			m_pTexture->LockRect( 0, &lr, NULL, 0 );
			memcpy( (D3DXFLOAT16*)lr.pBits, fHDR, 4*m_iWidth*m_iHeight * sizeof( D3DXFLOAT16 ) );

			m_pTexture->UnlockRect( 0 );

			// Set the raw data pointer
			m_iRawDataStride = 3*sizeof(float);
			m_pRawData = fHDRPixels;

			delete[] fHDR;

			m_bIsLoaded = true;
			return true;
		}
		coreGetLog()->WriteError("Unable to open HDR texture " + filename, __FILE__, __LINE__);
		return false;
	}
	else {
		D3DFORMAT targetformat;
		D3DXIMAGE_INFO info;

		if ( FAILED( D3DXGetImageInfoFromFile( filename.c_str(), &info) )) 
		{
			coreGetLog()->WriteError("Could not get image info from file " + filename, __FILE__, __LINE__);
		}

		m_iWidth = info.Width;
		m_iHeight = info.Height;
		m_iDepth = info.Depth;

		targetformat = info.Format;
		if (format != DEFAULT) {
			targetformat = convertFormatToD3D(format);
		}
		
		m_eFormat = convertFormatFromD3D( targetformat);

		DWORD usage = D3DUSAGE_DYNAMIC;
		if (dynamic) 
			usage = D3DUSAGE_DYNAMIC;

		Renderer *r = dynamic_cast<Renderer*>( coreGetRenderer() );
		bool vtex = r->IsTextureFormatOk( targetformat, r->getAdapterFormat(), D3DUSAGE_QUERY_VERTEXTEXTURE);

		if (m_iDepth == 1) {
			// Create the texture
			if( FAILED( D3DXCreateTextureFromFileEx( pd3dDevice,
													filename.c_str(),	// Source file
													D3DX_DEFAULT,		// Width
													D3DX_DEFAULT,		// Height
													D3DX_DEFAULT,		// MipLevels
													usage,				// Usage
													targetformat,		// Target Format
													D3DPOOL_DEFAULT,	// Pool
													D3DX_FILTER_NONE,	// Filter
													D3DX_FILTER_NONE,	// MipFilter
													0xFF000000,			// ColorKey
													&info,				// Source Info
													NULL,				// Palette
													&m_pTexture ) ))
			{            
				coreGetLog()->WriteError("Could not find texture map: " + filename, __FILE__, __LINE__);
				return false;
			}

			// Get the description of the surface
			m_pTexture->GetLevelDesc(0, &desc);

			pPixelAddress = (unsigned char*) malloc( sizeOfFormat( desc.Format ) );

			if (!dynamic) {
				// Create mipmap levels for the 2D Texture
				if ( FAILED( D3DXFilterTexture( m_pTexture, NULL, D3DX_DEFAULT, D3DX_DEFAULT) ))
				{
					coreGetLog()->WriteError("Could not create direct3d mipmap levels.", __FILE__, __LINE__);
				}
			} else {
				// Copy the texture into the localble version
				if( FAILED( D3DXCreateTextureFromFileEx( pd3dDevice,
													filename.c_str(),	// Source file
													D3DX_DEFAULT,		// Width
													D3DX_DEFAULT,		// Height
													1,					// MipLevels
													D3DUSAGE_DYNAMIC,	// Usage
													targetformat,		// Target Format
													D3DPOOL_SYSTEMMEM,	// Pool
													D3DX_FILTER_NONE,	// Filter
													D3DX_FILTER_NONE,	// MipFilter
													0xFF000000,			// ColorKey
													&info,				// Source Info
													NULL,				// Palette
													&m_pTextureLockable ) ))
				{            
					coreGetLog()->WriteError("Could not find texture map for lockable version: " + filename, __FILE__, __LINE__);
					return false;
				}

				if (FAILED( m_pTextureLockable->GetSurfaceLevel(0, &m_pSurfaceLockable) ))
				{
					coreGetLog()->WriteError("Could not bind surface from texture lockable", __FILE__, __LINE__);
					return false;
				}
			}

			if (FAILED( m_pTexture->GetSurfaceLevel(0, &m_pRenderTargetSurface) ))
			{
				coreGetLog()->WriteError("Could not bind render target surface from texture", __FILE__, __LINE__);
				return false;
			}
		}
		else {
			// Create the volume texture
			if( FAILED( D3DXCreateVolumeTextureFromFile( pd3dDevice, filename.c_str(), &m_pVolTexture ) ))
			{            
				coreGetLog()->WriteError("Could not find texture map " + filename, __FILE__, __LINE__);
				return false;
			}
			m_bIsVolTexture = true;
		}
		
		coreGetLog()->WriteLog("Loading Texture " + filename + " successful", __FILE__, __LINE__);

		m_bIsLoaded = true;
		return m_bIsLoaded;
	}
}

bool Texture::computeNormalMap( const std::string &filename )
{
	// First load the texture
	load(filename, true);

	LPDIRECT3DTEXTURE9 pHeightMap = m_pTexture;
	D3DSURFACE_DESC desc;
	if (pHeightMap)
		pHeightMap->GetLevelDesc(0,&desc);

	if (FAILED( D3DXCreateTexture(pd3dDevice, desc.Width, desc.Height, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_pTexture) ))
	{
		coreGetLog()->WriteError("Unable to create texture for the normalmap", __FILE__, __LINE__);
		return false;
	}

	if (FAILED( D3DXComputeNormalMap( m_pTexture,
									  pHeightMap,
									  NULL, 
									  0,
									  D3DX_CHANNEL_LUMINANCE,
									  10.0f) )) 
	{
		coreGetLog()->WriteError("Unable to convert the heightmap to a normal map", __FILE__, __LINE__);
		return false;
	}

	m_bIsLoaded = true;
	return true;
}

D3DFORMAT Texture::convertFormatToD3D(eFormat format)
{
	switch (format) {
		case R8G8B8:		return D3DFMT_R8G8B8;
		case A8R8G8B8:		return D3DFMT_A8R8G8B8;
		case A16B16G16R16:	return D3DFMT_A16B16G16R16;
		case A16B16G16R16F:	return D3DFMT_A16B16G16R16F;
		case A32B32G32R32F:	return D3DFMT_A32B32G32R32F;
		case G16R16F:		return D3DFMT_G16R16F;
		case R32F:			return D3DFMT_R32F;
		case R16F:			return D3DFMT_R16F;
		case X8R8G8B8:		return D3DFMT_X8R8G8B8;
		case D24S8:         return D3DFMT_D24S8;
		case L8:            return D3DFMT_L8;
		default:			return D3DFMT_X8R8G8B8;
	}
}


eFormat Texture::convertFormatFromD3D(D3DFORMAT format)
{
	switch (format) {
		case D3DFMT_R8G8B8:		return R8G8B8;
		case D3DFMT_A8R8G8B8:		return A8R8G8B8;
		case D3DFMT_A16B16G16R16:	return A16B16G16R16;
		case D3DFMT_A16B16G16R16F:	return A16B16G16R16F;
		case D3DFMT_A32B32G32R32F:	return A32B32G32R32F;
		case D3DFMT_G16R16F:		return G16R16F;
		case D3DFMT_R32F:			return R32F;
		case D3DFMT_R16F:			return R16F;
		case D3DFMT_X8R8G8B8:		return X8R8G8B8;
		case D3DFMT_D24S8:         return D24S8;
		case D3DFMT_L8:            return L8;
		default:			return X8R8G8B8;
	}
}

bool Texture::createRenderTarget(int width, int height, eFormat format, bool useDepth)
{
	m_iWidth = width;
	m_iHeight = height;
	m_eFormat = format;
	// Get backbuffer format to create the render target in the same format
	Renderer* renderer = (Renderer*)coreGetRenderer();

	D3DFORMAT d3DFormat = convertFormatToD3D(format);


	// create texture
	if (FAILED (pd3dDevice->CreateTexture(  m_iWidth,						// The width of the texture
											m_iHeight,						// The height of the texture
											1,								// Mipmap count (no mipmaps here
											D3DUSAGE_RENDERTARGET,			// The usage of the texture (obviously a render target)
											d3DFormat,						// The format as queried earlier
											D3DPOOL_DEFAULT,				// The pool, where the texture should be placed in
											&m_pTexture,					// A pointer to the texture object
											NULL ) ))						// The shared handle (Reserved, so NULL)
	{
		coreGetLog()->WriteError("Could not create render target texture", __FILE__, __LINE__);
		return false;
	}

	if (FAILED( m_pTexture->GetSurfaceLevel(0, &m_pRenderTargetSurface) ))
	{
		coreGetLog()->WriteError("Could not bind render target surface from texture", __FILE__, __LINE__);
		return false;
	}
	
	D3DSURFACE_DESC desc;
	m_pRenderTargetSurface->GetDesc( &desc );

	if (useDepth) {
		m_bHasDepthBuffer = true;
		if (FAILED( pd3dDevice->CreateDepthStencilSurface( desc.Width, desc.Height, D3DFMT_D24S8,  
												renderer->getMultisampleType(), 0, TRUE,
												&m_pRenderTargetDepthStencilSurface,
												NULL) ))
		{
			coreGetLog()->WriteError("Failed to create depth stencil surface for render target", __FILE__, __LINE__);
			m_bHasDepthBuffer = false;
		}
	}
	m_bIsRenderTarget = true;

	coreGetLog()->WriteLog("Render target successfully created", __FILE__, __LINE__);

	m_bIsLoaded = true;
	return true;
}

bool Texture::createRenderToTexture(int width, int height, eFormat format, bool usedepth)
{
	m_iWidth = width;
	m_iHeight = height;
	m_eFormat = format;
	m_sViewport.Width = m_iWidth;
	m_sViewport.Height = m_iHeight;

	// Get backbuffer format to create the render target in the same format
	Renderer* renderer = (Renderer*)coreGetRenderer();

	D3DFORMAT d3DFormat = convertFormatToD3D(m_eFormat);

	// create texture
	if (FAILED (pd3dDevice->CreateTexture(  m_iWidth,						// The width of the texture
											m_iHeight,						// The height of the texture
											1,								// Mipmap count (no mipmaps here
											D3DUSAGE_RENDERTARGET,			// The usage of the texture (obviously a render target)
											d3DFormat,						// The format as queried earlier
											D3DPOOL_DEFAULT,				// The pool, where the texture should be placed in
											&m_pTexture,					// A pointer to the texture object
											NULL ) ))						// The shared handle (Reserved, so NULL)
	{
		coreGetLog()->WriteError("Could not create render target texture", __FILE__, __LINE__);
		return false;
	}

	if (FAILED( D3DXCreateRenderToSurface(pd3dDevice, m_iWidth, m_iHeight, d3DFormat, usedepth, D3DFMT_D24S8, &m_pRTS) )) 
	{
		coreGetLog()->WriteError("Could not create render to surface object", __FILE__, __LINE__);
		return false;
	}

	if (FAILED( m_pTexture->GetSurfaceLevel(0, &m_pRenderTargetSurface) ))
	{
		coreGetLog()->WriteError("Could not bind render target surface from texture", __FILE__, __LINE__);
		return false;
	}

	m_sViewport.X = 0; 
	m_sViewport.Y = 0;
	m_sViewport.Width = m_iWidth;
	m_sViewport.Height = m_iHeight;
	m_sViewport.MinZ = 0.0f;
	m_sViewport.MaxZ = 1.0f;

	m_bIsLoaded = true;
	m_bIsRenderTarget = true;

	return true;
}

bool Texture::createFromData(int width, int height, eFormat format, char* data)
{
	m_iWidth = width;
	m_iHeight = height;
	m_eFormat = format;

	D3DFORMAT d3DFormat = convertFormatToD3D(m_eFormat);

	// create texture
	if (FAILED (pd3dDevice->CreateTexture(  m_iWidth,						// The width of the texture
											m_iHeight,						// The height of the texture
											1,								// Mipmap count (no mipmaps here
											D3DUSAGE_DYNAMIC,			// The usage of the texture (obviously a render target)
											d3DFormat,						// The format as queried earlier
											D3DPOOL_DEFAULT,				// The pool, where the texture should be placed in
											&m_pTexture,					// A pointer to the texture object
											NULL ) ))						// The shared handle (Reserved, so NULL)
	{
		coreGetLog()->WriteError("Could not create target texture", __FILE__, __LINE__);
		return false;
	}

	int v = 255;
	int n = 0;

	D3DLOCKED_RECT rect;
	m_pTexture->LockRect(0, &rect, NULL, D3DLOCK_DISCARD);
	int Bpp = rect.Pitch / m_iWidth;
	for (int y=0; y<m_iHeight; ++y) {
		for (int x=0; x<m_iWidth; ++x) {
			memcpy(((unsigned char*)rect.pBits) + y * rect.Pitch + x * Bpp,     &data[y*Bpp*m_iWidth + Bpp*x+2], sizeof(char));
			memcpy(((unsigned char*)rect.pBits) + y * rect.Pitch + x * Bpp + 1, &data[y*Bpp*m_iWidth + Bpp*x+1], sizeof(char));
			memcpy(((unsigned char*)rect.pBits) + y * rect.Pitch + x * Bpp + 2, &data[y*Bpp*m_iWidth + Bpp*x+0], sizeof(char));
			memcpy(((unsigned char*)rect.pBits) + y * rect.Pitch + x * Bpp + 3, &data[y*Bpp*m_iWidth + Bpp*x+3], sizeof(char));
		}
	}
	m_pTexture->UnlockRect(0);

 	return true;
}

bool Texture::beginScene()
{	
	if (FAILED( m_pRTS->BeginScene(m_pRenderTargetSurface, &m_sViewport)) )
	{
		coreGetLog()->WriteError("Could not begin scene for render target", __FILE__, __LINE__);
		return false;
	}
	pRenderer->setBackBufferSize(math::Vector2i(m_iWidth, m_iHeight));	
	
	return true;
}

bool Texture::endScene()
{
	if (FAILED( m_pRTS->EndScene(D3DX_FILTER_NONE)) )
	{
		coreGetLog()->WriteError("Could not end scene for render target", __FILE__, __LINE__);
		return false;
	}
	pRenderer->resetBackBufferSize();
	return true;
}

bool Texture::bind(unsigned int uiTexTarget)
{
	D3DLOCKED_RECT rect;
	D3DLOCKED_BOX  box;

	if ( !isLoaded() )
	{
		coreGetLog()->WriteWarning("Can't bind texture. No texture loaded", __FILE__, __LINE__);
		return false;
	}

	m_iCurrentTarget = uiTexTarget;

	// Check for redundant sets
	if ( s_ppCurrentTextures[m_iCurrentTarget] == this ) {
		return true;
	}

	if ( !isVolumeTexture() ) {
		
		if ( !isRenderTarget() ) {
			if ( FAILED(m_pTexture->LockRect(0, &rect, NULL, 0)) ) 
			{
				coreGetLog()->WriteError("Could not lock Texture", __FILE__, __LINE__);
				return false;
			}

			pd3dDevice->SetSamplerState( m_iCurrentTarget, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
			pd3dDevice->SetSamplerState( m_iCurrentTarget, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
			pd3dDevice->SetTexture(m_iCurrentTarget, m_pTexture );

			m_pTexture->UnlockRect(0);
		}
		else {
			//pd3dDevice->SetSamplerState( m_iCurrentTarget, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
			//pd3dDevice->SetSamplerState( m_iCurrentTarget, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
			pd3dDevice->SetTexture(m_iCurrentTarget, m_pTexture );
		}
	} 
	else {
		if ( FAILED(m_pVolTexture->LockBox(0, &box, NULL, 0)) ) 
		{
			coreGetLog()->WriteError("Could not lock Texture", __FILE__, __LINE__);
			return false;
		}

		pd3dDevice->SetTexture(m_iCurrentTarget, m_pVolTexture);

		m_pVolTexture->UnlockBox(0);
	}

	s_ppCurrentTextures[m_iCurrentTarget] = this;

	return true;
}

bool Texture::unbind()
{
	if ( !isLoaded() ) {
		coreGetLog()->WriteWarning("Can't unbind texture. No texture loaded", __FILE__, __LINE__);
		return false;
	}

	// Unlock the texture for the render target
	//if (isRenderTarget() && pRenderTargetSurface)
	//	pRenderTargetSurface->UnlockRect();

	pd3dDevice->SetTexture(m_iCurrentTarget, 0);
	// Unset the currentTarget
	s_ppCurrentTextures[m_iCurrentTarget] = 0;
	m_iCurrentTarget = -1;

	return true;
}

IDirect3DTexture9* Texture::getD3DTexture() const
{
	return m_pTexture;
}

IDirect3DVolumeTexture9* Texture::getD3DVolumeTexture() const
{
	return m_pVolTexture;
}

IDirect3DSurface9* Texture::getRenderTarget() const
{
	return m_pRenderTargetSurface;
}

IDirect3DSurface9* Texture::getRenderTargetDepthStencil() const
{
	return m_pRenderTargetDepthStencilSurface; 
}


// This function needs to be more performant!!!!
void Texture::display(int offsetX, int offsetY, float scaleFactor, bool bIgnoreBlend, const math::Vector4 &color, bool enableFilter)
{
	static SHADERHANDLE hOffset;
	static SHADERHANDLE hDimension;
	static SHADERHANDLE hTex;
	static SHADERHANDLE hTex2;
	static SHADERHANDLE hScreenSize;
	static SHADERHANDLE hFilteredTech;
	static SHADERHANDLE hDefaultTech;
	
	static math::Vector2i offset;
	static math::Vector2f dimension;

	if (!pEffect) {
		pEffect = coreGetResourceFactory()->loadShaderEffect("/data/shader/texdisp.fx");
		hOffset    = pEffect->getParameterByName("offset");
		hDimension = pEffect->getParameterByName("dimension");
		hTex       = pEffect->getParameterByName("mainTex");
		hTex2      = pEffect->getParameterByName("filterTex");
		hScreenSize = pEffect->getParameterByName("screenSize");
		hFilteredTech = pEffect->getParameterByName("Filtered");
		hDefaultTech = pEffect->getParameterByName("Default");
		math::Vector2f size = math::Vector2f(2.0f/pRenderer->getBackBufferSize().x, 2.0f/pRenderer->getBackBufferSize().y);
		pEffect->setFloat(hScreenSize, &size.x, 2);
	}

	if (!m_pScreenQuad)
		m_pScreenQuad = IDrawPrimitive::CreateQuad(1, 1, color);

	offset    = math::Vector2i(offsetX, offsetY);
	dimension = math::Vector2f(m_iWidth * scaleFactor, m_iHeight * scaleFactor);

	if (enableFilter) {
		pEffect->setTexture(hTex, NULL);
		pEffect->setTexture(hTex2, this);
		pEffect->setTechnique(hFilteredTech);
	} else {
		pEffect->setTexture(hTex, this);
		pEffect->setTexture(hTex2, NULL);
		pEffect->setTechnique(hDefaultTech);
	}
	if (pEffect->bind()) {
		if (pEffect->beginPass(0)) {
			pEffect->setInt(hOffset, &offset.x, 2);
			pEffect->setFloat(hDimension, &dimension.x, 2);
			pEffect->setVariables();
			pRenderer->drawPrimitive(m_pScreenQuad);
			pEffect->endPass();
		}
		pEffect->unbind();
	}

/*
	bind();
	if ((m_eFormat == A8R8G8B8 || m_eFormat == A16B16G16R16F) && !bIgnoreBlend)
	{
		// Enable alpha blending
		pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		// Set the source blend state.
		pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
		// Set the destination blend state.
		pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
		
		// Draw the screen quad
		//coreGetRenderer()->drawScreenQuad(m_iWidth, m_iHeight, offsetX, offsetY, scaleFactor);
		pRenderer->drawPrimitive(m_pScreenQuad);
		// Disable alpha blending
		//pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
	} else {
		//pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
//		coreGetRenderer()->drawScreenQuad(m_iWidth, m_iHeight, offsetX, offsetY, scaleFactor);
		pRenderer->drawPrimitive(m_pScreenQuad);
	}

	DELETE_POINTER(m_pScreenQuad);
	// Unbind the texture
	unbind();
*/
}

unsigned char* Texture::getPixel(unsigned int x, unsigned int y)
{
	if (x >= desc.Width || y >= desc.Height)
		return 0;
	// Set the pixel address to 0
	//memset(pPixelAddress, 0, sizeOfFormat( desc.Format ));
	if (m_pSurfaceLockable) {
		synchronized(g_mutex) {
			if (SUCCEEDED( m_pSurfaceLockable->LockRect(&lr, NULL, D3DLOCK_READONLY) )) {
				int Bpp = lr.Pitch / desc.Width;
				unsigned char *p = ( (unsigned char*)lr.pBits ) + x * Bpp + y * lr.Pitch;
				memcpy_s(pPixelAddress, Bpp, p, Bpp);

				m_pSurfaceLockable->UnlockRect( );
			} else {
				coreGetLog()->WriteError("Failed to lock texture for pixel access", __FILE__, __LINE__);
			}
		}
	} else if (m_pRTS) {
		synchronized(g_mutex) {
			if (SUCCEEDED( m_pRenderTargetSurface->LockRect(&lr, NULL, D3DLOCK_READONLY) )) {
				int Bpp = lr.Pitch / desc.Width;
				unsigned char *p = ( (unsigned char*)lr.pBits ) + x * Bpp + y * lr.Pitch;
				memcpy_s(pPixelAddress, Bpp, p, Bpp);

				m_pRenderTargetSurface->UnlockRect( );
			} else {
				coreGetLog()->WriteError("Failed to lock texture for pixel access", __FILE__, __LINE__);
			}
		}
	}

	return pPixelAddress;
}

const unsigned int Texture::sizeOfFormat(D3DFORMAT format) const
{
	switch (format) {
		case L8:
			return 8;
		case D3DFMT_R16F:
			return 16;
			break;
		case D3DFMT_R8G8B8:
			return 24;
		case D3DFMT_A8R8G8B8:
		case D3DFMT_G16R16F:
		case D3DFMT_R32F:
		case D3DFMT_D24S8:
			return 32;
		case D3DFMT_A16B16G16R16:
		case D3DFMT_A16B16G16R16F:
			return 64;
		case D3DFMT_A32B32G32R32F:
			return 128;
		default:
			return 0;
	}
	return 0;
}

} // namespace
